package com.graph.similar;

import com.sun.org.apache.regexp.internal.RE;

/**
 * @author LiWu
 */
public class ConsineSimilar {

    /**
     * 余弦相似度的计算
     * @param matrix
     * @param i
     * @param j
     * @return
     */
    public double cosine(int[][] matrix, int i, int j){ //cosine measure
        if(i == j){
            return 1;
        }
        int k = 0;
        int ai = 0;
        int aj = 0;
        int aij = 0;
        for(k = 0;k < matrix[i].length; k ++){
            if(matrix[i][k] != 0 && matrix[j][k] != 0){
                aij ++;
            }
            if(matrix[i][k] != 0){
                ai ++;
            }
            if(matrix[j][k] != 0){
                aj ++;
            }
        }
        if(ai == 0 || aj == 0){
            return 0;
        }
        return aij / (Math.sqrt(ai * aj));
    }

    public double r(int[][] matrix, int i, int j){
        double a = 0,b = 0;
        for(int k = 0;k < matrix.length;k ++){
            if(i != k){
                a = a + cosine(matrix, i, k) * matrix[k][j];
                b = b + cosine(matrix, i, k);
            }
        }
        return a / b;
    }

    public double[][] predict(int[][] matrix){
        double[][] pred = new double[matrix.length][matrix[0].length];
        for(int i = 0;i < matrix.length;i ++){
            for(int j = 0;j < matrix[i].length;j ++){
                pred[i][j] = r(matrix, i, j);
            }
        }
        return pred;
    }

    public double comErr(int[][] matrix){ //compute the error of the predicting result
        double[][] predictMat = new double[matrix.length][matrix[0].length];
        predictMat = predict(matrix);
        double meanErr = 0;
        for(int i = 0;i < matrix.length;i ++){
            for(int j = 0;j<matrix[i].length;j ++){
                meanErr = meanErr + Math.abs(predictMat[i][j] - matrix[i][j]);
            }
        }
        double a = matrix.length;
        return meanErr / a;
    }

    public static void main(String args[]){
        ConsineSimilar sim = new ConsineSimilar();
        int mat[][] = {{5,3,0,1}, {4,0,0,1}, {1,1,0,5}, {1,0,0,4}, {0,1,5,4}};
        for(int i = 0;i < mat.length;i ++){
            for(int j = 0;j < mat.length;j ++){
                System.out.printf("%1.12f", sim.cosine(mat, i, j));
                System.out.print("   ");
            }
            System.out.println();
        }
        System.out.println("以上是相似度矩阵");

        double[][] pre = sim.predict(mat);
        for(int i = 0;i < mat.length;i ++){
            for(int j = 0;j < mat[i].length;j ++){
                System.out.printf("%1.12f", pre[i][j]);
                System.out.print("   ");
            }
            System.out.println();
        }
        System.out.println("以上是预测结果");
        System.out.println(sim.comErr(mat));
        System.out.println("以上是平均误差");
    }
}
